#include "athd.h"
void listout(ath_list *tlist);
void safe_print(char *str, ...);

void * thread_test1(void *ctx);
void * thread_test2(void *ctx);

pthread_mutex_t print_mutex;
apr_pool_t *pglobal;

int 
main(int argc, const char * const argv[])
{
    char *str;
    const char *str_conffile = ATHD_DEFAULT_CONFFILE;
    const char *optarg;
    int rv, i;
    char c;
    athd_conf *conf;
    char *str_msg;
    ath_list *tlist;
    pthread_t thread1;
    pthread_t thread2;

    pthread_mutex_init(&print_mutex, NULL);

    safe_print("tester: v %s init pid: %d", ATH_VERSION_STRING, getpid());

    apr_app_initialize(&argc, &argv, NULL);
    atexit(apr_terminate);
    apr_pool_create(&pglobal, NULL);

    tlist = ath_list_ap_alloc(pglobal);

    for (i = 0; i < 8; i++)
      {
	  str = apr_psprintf(pglobal, "(el-%d)", i);
	  ath_list_ap_add(pglobal, tlist, str);
	  safe_print("added: %s", str);
      }

    safe_print("list size: %ld", ath_list_size(tlist));

    str = (char *) ath_list_idx(tlist, 6);
    safe_print("list idx test: idx[%d]: %s", 6, str);

    for (i = 0; i < 10; i++)
      {
	  str = (char *) ath_list_getnext(tlist);
	  safe_print("list el[%d]: %s has next: %d is head: %d", 
		   i, str, ath_list_hasnext(tlist), ath_list_at_head(tlist));
      }

    safe_print("%s", "delete test ...");
    ath_list_remove_prev(tlist);
    safe_print("list size: %ld", ath_list_size(tlist));

    safe_print("%s", "rewinding for rewind test ...");
    ath_list_rewind(tlist);

    for (i = 0; i < 12; i++)
      {
	  str = (char *) ath_list_getnext(tlist);
	  safe_print("list el[%d]: %s has next: %d is head: %d", 
		   i, str, ath_list_hasnext(tlist), ath_list_at_head(tlist));
      }
  
    safe_print("%s", "rewinding for while test ...");
    ath_list_rewind(tlist);

    while (ath_list_hasnext(tlist))
      {
	  str = (char *) ath_list_getnext(tlist);
	  safe_print("list el: %s has next: %d is head: %d", 
		   str, ath_list_hasnext(tlist), ath_list_at_head(tlist));
      }

    safe_print("%s", "delete head test ...");
    ath_list_remove_cur(tlist);
    safe_print("list size: %ld", ath_list_size(tlist));
    safe_print("%s", "rewinding for another while test ...");
    ath_list_rewind(tlist);

    while (ath_list_hasnext(tlist))
      {
	  str = (char *) ath_list_getnext(tlist);
	  safe_print("list el: %s has next: %d is head: %d", 
		   str, ath_list_hasnext(tlist), ath_list_at_head(tlist));
      }

    
    safe_print("%s", "delete to one test ...");
    ath_list_rewind(tlist);
    while (ath_list_hasnext(tlist))
      {
	  str = (char *) ath_list_getnext(tlist);
	  safe_print("DELETE list el: %s has next: %d is head: %d", 
		   str, ath_list_hasnext(tlist), ath_list_at_head(tlist));
	  ath_list_remove_prev(tlist);
	  listout(tlist);
      }
    
    safe_print("%s", "rebuilding for pop test ...");
    for (i = 0; i < 8; i++)
      {
	  str = apr_psprintf(pglobal, "(el-%d)", i);
	  ath_list_ap_add(pglobal, tlist, str);
	  safe_print("added: %s", str);
      }
    safe_print("list size: %ld", ath_list_size(tlist));
    ath_list_rewind(tlist);
    while (ath_list_hasnext(tlist))
      {
	  str = (char *) ath_list_popnext(tlist);
	  safe_print("DELETE list el: %s has next: %d is head: %d", 
		   str, ath_list_hasnext(tlist), ath_list_at_head(tlist));
	  listout(tlist);
      }

    safe_print("rebuilding for threads test");
/*     for (i = 0; i < 0; i++) */
/*       { */
/* 	  str = apr_psprintf(pglobal, "(el-%d)", i); */
/* 	  ath_list_ap_add(pglobal, tlist, str); */
/* 	  safe_print("added: %s", str); */
/*       } */

    safe_print("list size: %d", ath_list_size(tlist));
    safe_print("list isempty: %d", ath_list_isempty(tlist));
    pthread_create(&thread1, NULL, thread_test1, (void *)tlist);
    apr_sleep(XTH_SEC(1000));
    pthread_create(&thread2, NULL, thread_test2, (void *)tlist);

    pthread_join(thread2, &str);
    safe_print("%s", str);
    pthread_cancel(thread1);
    str = NULL;
    pthread_join(thread1, &str);
    //safe_print("%s", str ? str : "NULL");
    listout(tlist);


}

void
listout(ath_list *tlist)
{
    char *str;
    ath_node *ctx;
    safe_print("hasnext: %d", ath_list_hasnext(tlist)); 
    ath_list_rewind_r(tlist, &ctx);
    while (ath_list_hasnext_r(tlist, &ctx))
      {
	  str = (char *) ath_list_getnext_r(tlist, &ctx);
	  safe_print(" -- list el: %s has next: %d is head: %d", 
		   str, ath_list_hasnext_r(tlist, &ctx), 
		   ath_list_at_head_r(tlist, &ctx));
      }
}

void *
thread_test1(void *ctx)
{
    int i, j = 0;
    ath_list *list = (ath_list *)ctx;
    int laststate, lasttype;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &laststate);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &lasttype);
    for (;;)
      {
	  safe_print("%s looped (size: %lld)", __FUNCTION__, ath_list_size(list));
	  for (i = 0; i < 4; i++)
	    {
		char *str = apr_psprintf(pglobal, "(tel-%d-%d)", j, i);
		ath_list_ap_add_tail(pglobal, list, str);
		safe_print("%s added: %s %d", __FUNCTION__, str, str);
		j++;
		pthread_testcancel();
	    }
      }
    safe_print("leaving thread1");
    pthread_exit((void *)"left thread1");
}

void *
thread_test2(void *ctx)
{
    int i;
    ath_list *list = (ath_list *)ctx;
    while (!ath_list_isempty(list))
      {
	  safe_print("%s looped (size: %lld)", __FUNCTION__, ath_list_size(list));
	  for (i = 0; (i < 20) && (!ath_list_isempty(list)); i++)
	    {
		char *str;
		str = ath_list_popnext(list);
		safe_print("%s popped: %s %d", __FUNCTION__, str, str);
	    }
      }
    safe_print("leaving thread2");
    pthread_exit((void *)"left thread2");
}

void
safe_print(char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    pthread_mutex_lock(&print_mutex);
    fprintf(stdout, "%s(%d,%s): ", __FILE__, __LINE__, __FUNCTION__);
    vfprintf(stdout, fmt, args);
    fprintf(stdout, "\n");
    pthread_mutex_unlock(&print_mutex);
    va_end(fmt);
}
